import { checkOpusIsStereo, copyCandidate, findIp, getOpusFormatNumber, mungeSdpForceStereoOpus } from "@/utils/index"
import { cloneDeep } from "lodash"

/**
 *  ws 暂时只支持ip
 */
export default class LinkWebRc {
    ws: string
    WebSocket: WebSocket
    wsConnected: boolean
    pc: RTCPeerConnection
    // pc = new RTCPeerConnection();
    videoElement: HTMLVideoElement

    constructor(ws: string, videoElement: HTMLVideoElement) {
        this.ws = ws
        this.videoElement = videoElement
        this.initWebSocket()

    }
    onSuccess:Function
    onError:Function
    onClose:Function
    initWebSocket() {
        this.WebSocket = new WebSocket(this.ws);
        this.WebSocket.onopen = (ev: Event) => {
            this.wsConnected = true;

            this.sendMessage({
                command: "request_offer"
            });
        };
        this.WebSocket.onmessage = (ev: MessageEvent) => this.message(ev);
        this.WebSocket.onerror = (ev: Event) => this.error(ev);
        this.WebSocket.onclose = (ev: CloseEvent) => this.close(ev);
    }
    playDps() { }
    message(e: MessageEvent) {
        const message = JSON.parse(e.data);
        if (message.code === 404) {
            this.onError(()=>{
                this.WebSocket.close()
                this.onError ?this.onError() : null
            })
            return
        }
        else{
            this.onSuccess ? this.onSuccess() : null
        }
        if (Object.keys(message).length === 0 && message.constructor === Object) {
            console.log("Empty Message");
            return;
        }

        if (message.command === "ping") {
            this.sendMessage({ command: "pong" });
            return;
        }
        if (message.command === 'offer') {
            this.createMainPeerConnection(message)
        }
    }
    error(e: Event) {
        console.error("linkWebRc 错误：", e)
    }
    close(e: CloseEvent) {
        console.log("关闭", e)
        this.onClose()
    }
    sendMessage(message: any) {
        if (this.WebSocket) {
            this.WebSocket.send(JSON.stringify(message));
        } else {
            console.error("WebSocket is null")
        }
    }
    createMainPeerConnection(message: any) {
        const slef = this
        let iceServers = message.iceServers || message.ice_servers;
        if (!iceServers || iceServers.length === 0) {
            console.error('iceServers is emp')
            return
        }
        let socketip = findIp(cloneDeep(this.ws))
        for (let index = 0; index < iceServers.length; index++) {
            const { urls } = iceServers[index]
            const url = cloneDeep(urls[0])
            const ip = findIp(url)
            iceServers[index].urls.push(url.replace(ip, socketip))

        }
        // console.log(iceServers)
        let peerConnection = new RTCPeerConnection({
            iceTransportPolicy: "relay",
            iceServers
        });

        peerConnection.setRemoteDescription(new RTCSessionDescription(message.sdp)).then(() => {

            peerConnection.createAnswer().then(function (desc) {

                const opusFormatNumber = getOpusFormatNumber(message.sdp.sdp);

                if (opusFormatNumber > -1) {

                    if (checkOpusIsStereo(message.sdp.sdp, opusFormatNumber)) {

                        //If offer has opus and if it is stereo, munge local sdp to force stereo=1
                        //Thanks to community https://github.com/AirenSoft/OvenMediaEngine/issues/203
                        desc.sdp = mungeSdpForceStereoOpus(desc.sdp, opusFormatNumber);
                    }
                }

                slef.sendMessage({
                    id: message.id,
                    peer_id: message.peer_id,
                    command: 'answer',
                    sdp: desc
                });

                console.log("create Host Answer : success");

                peerConnection.setLocalDescription(desc).then(function () {


                }).catch(function (error) {
                    console.log(error)
                });
            }).catch(function (error) {

                console.log(error)
            });

        })
        if (message.candidates) {

            this.addIceCandidate(peerConnection, message.candidates);
        }
        peerConnection.onicecandidate = function (e) {

            if (e.candidate) {

                console.log("WebRTCLoader send candidate to server : ", e.candidate);

                // console.log('Main Peer Connection candidate', e.candidate);
                slef.sendMessage({
                    id: message.id,
                    peer_id: message.peer_id,
                    command: "candidate",
                    candidates: [e.candidate]
                });
            }
        };

        peerConnection.onconnectionstatechange = function (e) {
            //ConnectionState
            console.log("[on connection state change]", peerConnection.connectionState, e);

            // firefox and opera do not support onconnectionstatechange (Jan 07, 2021)
            // double check with oniceconnectionstatechange
            if (peerConnection.connectionState === 'connected') {

                console.log("connectedCallback")
            }
        };
        peerConnection.oniceconnectionstatechange = (e) => { }
        peerConnection.ontrack = function (event) {
            // loadCallback(e.streams[0]);
            if (slef.videoElement['srcObject'] !== event.streams[0]) {
                const videoTracks = event.streams[0].getVideoTracks();
                const audioTracks = event.streams[0].getAudioTracks();
                slef.videoElement['srcObject'] = event.streams[0];

            }
        }
    }
    addIceCandidate(peerConnection: RTCPeerConnection, candidates: any) {

        for (let i = 0; i < candidates.length; i++) {
            if (candidates[i] && candidates[i].candidate) {

                let basicCandidate = candidates[i];

                peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate)).then(function () {
                    console.log("addIceCandidate : success");
                }).catch(function (error) {
                    console.log(error)
                });

                let cloneCandidatePromise = copyCandidate(basicCandidate, this.ws);

                if (cloneCandidatePromise) {
                    cloneCandidatePromise.then(function (cloneCandidate) {

                        if (cloneCandidate) {

                            peerConnection.addIceCandidate(new RTCIceCandidate(cloneCandidate)).then(function () {
                                console.log("cloned addIceCandidate : success");

                            }).catch(function (error) {

                                console.error(error)
                            });
                        }
                    });
                }
            }
        }
    }
}